package edu.umd.ion.wavemeter.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.BeforeSelectionEvent;
import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

import edu.umd.ion.wavemeter.service.WavemeterData;
import edu.umd.ion.wavemeter.service.WavemeterDataMask;
import edu.umd.ion.wavemeter.service.WavemeterService;
import edu.umd.ion.wavemeter.service.WavemeterServiceAsync;

/**
 * Entry-Point of the client browser application. It contains the Tab Panel which in turn
 * contains the different widgets for Display, Control, Settings.
 * @author monroe-lab
 * 
 */

public class wavemeter implements EntryPoint {
	private WavemeterServiceAsync serviceProxy;
	private WavemeterDataMask dataMask;
   	private TabPanel MainTabPanel;
	private boolean PollActive = true, WaitingForResponse = false;
	
	// Widgets
	private WavemeterWidget DisplayWidget;
	private ControlWidget ControlDisplay;
	private Settings SettingsDisplay;
	private HTML DataErrorMessage = new HTML();
	private HTML CommandErrorMessage = new HTML();
	private long timeBeforeCall;
	private long timeAfterCallback;
	private long timeAtInitialization;
	private int PatternCount;
	private VerticalPanel ErrorPanel;
	private HorizontalPanel CalibrationPopup;
	private CalibrationHistoryWidget CalibrationHistory;
	private VerticalPanel Application = new VerticalPanel();
	private StyleSheetManager styleSheetManager;

	
	private native void reload() /*-{
	    $wnd.location.reload();
	   }-*/;

	// Callbacks
	private AsyncCallback<Boolean> IsLocalCallback = new AsyncCallback<Boolean>() {
		@Override
		public void onFailure(Throwable caught) {
			// ignore
		}
		@Override
		public void onSuccess(Boolean result) {
			if (ControlDisplay==null && result) {
				ControlDisplay = new ControlWidget( serviceProxy, ErrorPanel );
				MainTabPanel.add(ControlDisplay,"Control");
			}
		}
	};
	
	private AsyncCallback<WavemeterData> DataCallback = new AsyncCallback<WavemeterData>()
	{
		public void onFailure (Throwable caught)
		{
			try {
				DataErrorMessage.setHTML( "Data: " + caught.getMessage() );
				dataMask.clearPatternRequest();
				WaitingForResponse = false;
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
				poll();
			}
		}
		public void onSuccess (WavemeterData data)
		{
			timeAfterCallback = System.currentTimeMillis();
			dataMask.SpinAroundTime = data.SpinAroundTime;
			dataMask.clearPatternRequest();
			DisplayWidget.set(data, dataMask);
			CalibrationHistory.set(data);
			if (ControlDisplay!=null) { ControlDisplay.set(data); }
			if (data.PatternList != null && data.PatternList.size() > 0) {
				PatternCount+=data.PatternList.size();
				DisplayWidget.setMessage(1, "pattern server response time: "
						+ (timeAfterCallback - timeBeforeCall)
						+ " client processing time: "
						+ (System.currentTimeMillis() - timeAfterCallback)
						+ " Patterns transmitted: "
						+ PatternCount);
			} else {
				long totalseconds = (System.currentTimeMillis() - timeAtInitialization)/1000;
				long seconds = totalseconds % 60;
				long minutes = (totalseconds/60) % 60;
				long hours = (totalseconds/3600);
				String Message = "server response time: " + (timeAfterCallback - timeBeforeCall)
					+ " client processing time: " + (System.currentTimeMillis() - timeAfterCallback)
					+ " Uptime: " + (hours>0?(String.valueOf(hours)+"h "):"") 
					+ (minutes>0?(String.valueOf(minutes)+"m "):"") + seconds + "s";
				DisplayWidget.setMessage(0, Message);
			}
			WaitingForResponse = false;
			DataErrorMessage.setHTML( "" );
			poll();
		}
	};

	private BeforeSelectionHandler<Integer> MainTabHandler = new BeforeSelectionHandler<Integer>(){
		@SuppressWarnings("unchecked")
		public void onBeforeSelection(BeforeSelectionEvent<Integer> e) {
			if (MainTabPanel.getWidget(e.getItem()) instanceof NeedsDataPoll) {
				if (!PollActive) {
					PollActive = true;
					poll();
				}
			} else {
				PollActive=false;
			}
			try {
				BeforeSelectionHandler<Integer> TabSelectionHandler = (BeforeSelectionHandler<Integer>) MainTabPanel.getWidget(e.getItem());
				TabSelectionHandler.onBeforeSelection(e);
			}
			catch (ClassCastException ignore) {
				// ignore it, the tab does not implement the Handler
			}
		}
	};
	
	public wavemeter() {
		dataMask = new WavemeterDataMask();
		timeAtInitialization = System.currentTimeMillis();
	}
	
	/** Polls the server for new measurements
	 */
	public void poll()
	{
		if (PollActive && !WaitingForResponse)
		{
			WaitingForResponse = true;
			timeBeforeCall = System.currentTimeMillis();
			serviceProxy.pollWavemeter(dataMask, DataCallback);
		}
	}
	
	/** Get the username (profile) in use.
	 * @return username
	 */
	public String myUsername()
	{
		return SettingsDisplay.myUsername();
	}
	
	/** Initialization of the client application 
	 * @see com.google.gwt.core.client.EntryPoint#onModuleLoad()
	 */
	public void onModuleLoad() 
	{	
		serviceProxy = GWT.create(WavemeterService.class);
		ErrorPanel = new VerticalPanel();
	    styleSheetManager = new StyleSheetManager(Application);
		
		DisplayWidget = new WavemeterWidget( serviceProxy, ErrorPanel, styleSheetManager );	
		SettingsDisplay = new Settings( serviceProxy, DisplayWidget );
		CalibrationPopup = new HorizontalPanel();
		CalibrationPopup.setWidth("100%");
		
		MainTabPanel = new TabPanel();
		MainTabPanel.add(DisplayWidget, "Display");
		MainTabPanel.add(SettingsDisplay, "Settings");
		CalibrationHistory = new CalibrationHistoryWidget(serviceProxy,ErrorPanel,CalibrationPopup);
		MainTabPanel.add(CalibrationHistory, "Calibration History");
		MainTabPanel.add(new ChannelRoutingWidget(serviceProxy,ErrorPanel), "Channel Routing");
		MainTabPanel.add(new ExposureParametersWidget(serviceProxy,ErrorPanel),"Exposure Parameters");
		MainTabPanel.setWidth("100%");
		MainTabPanel.selectTab(0);
		MainTabPanel.addBeforeSelectionHandler(MainTabHandler);
		
		serviceProxy.isLocalClient(IsLocalCallback);
		
		poll();
		
		Application.setWidth("100%");
		Application.add(CalibrationPopup);
		Application.add(MainTabPanel);
		Application.add(ErrorPanel);
		ErrorPanel.add(DataErrorMessage);
		ErrorPanel.add(CommandErrorMessage);

	    RootPanel.get("wavelength1").add(Application);
	}
	

}
